import pickle
import json
import os

def sidechain(func, data, *args, **kw):
	func(data, *args, **kw)
	return data

def listdir(path):
		return [ fn for v in [[ os.path.join(*b) for b in [ (a[0], c) for c in a[2]]] for a in [ [r,d,f] for r,d,f in os.walk(path)]] for fn in v]

def filename_from_key(key):return os.sep.join(key.split("::"))
def key_name( fn,dir): return fn[len(dir):fn.rfind('.')].replace(os.sep,"::").lower()[2:]
def key_from_path(*items): return "::".join(items).lower()

class Struct:
	def __init__(self,dat): self.__dict__.update([(key, Struct(val) if isinstance(val,dict) else val) for key,val in dat.items()])

load_struct = lambda fileobj: Struct(json.load(fileobj))

def save_data( dir, data,saver=json.dump,ext='.json',mode='w'):
	for key,obj in data.items():saver(obj,open(os.path.join(os.getcwd(),dir,filename_from_key(key)+ext),mode))

#A solution to pre-loading vs cache-ing.
#The load time for parsing all of this JSON
#Stuff was about to kill me. o_O
class Cache:
	def __init__(self,directory,opener=json.load,mode=['r'],oargs=[]):
		self.opener=opener
		self.dir=directory
		self.open_args=mode
		self.opener_args=oargs
		self.objects={}
		self.files={}
		path=os.path.join(os.getcwd(),self.dir)
		for fn in listdir(path):
			key=key_name(fn,path)
			self.files[key],self.objects[key]=fn,None

	def load_all(self):return [self[key] for key in self.objects.keys()]

	def keys(self):return self.objects.keys()

	def items(self):self.load_all();return self.objects.items()

	def values(self):self.load_all();return self.objects.values()

	def __getitem__(self,*items):
		item=key_from_path(*items)
		if self.objects[item] is None:
			f=open(self.files[item],*self.open_args) if len(self.open_args)>0 else open(self.files[item])
			self.objects[item]=self.opener(f,*self.opener_args) if len(self.opener_args)>0 else self.opener(f)
		return self.objects[item]

def load_data( dir,opener=json.load,mode='r'):
	ret = {}
	err = []
	for fn in listdir(os.path.join(os.getcwd(),dir)):
		try:
			ret[key_name(fn,os.path.join(os.getcwd(),dir))] = opener(open(fn,mode))
		except:
			err.append(key_name(fn,os.path.join(os.getcwd(),dir)))
	if len(err)>0:
		print("These items couldn't be loaded:")
		for i in err:print("\t{}".format(i))
	return ret

